using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Pipes;
using System.Linq;
using System.Security.Principal;
using System.Threading;
using System.Timers;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Simulation;

namespace Kinixt
{
    public class SimulationGame : Xnaml.Game
    {
        Xnaml.GraphicsDeviceManager graphics;
        KeyboardState currentKeyboardState;
        GamePadState currentGamePadState;
        MouseState currentMouseState;
        Robot robot;
        Ground ground;
        BehindHeadCamera camera;

        /// <summary>
        /// Initiates simulation
        /// </summary>
        public SimulationGame()
        {
            if (!DesignTime)
            {
                graphics = new Xnaml.GraphicsDeviceManager(this);
                graphics.SupportedOrientations = DisplayOrientation.Portrait;
                graphics.ApplyChanges();

                Content.RootDirectory = "Content";
                IsMouseVisible = true;

                camera = new BehindHeadCamera();
                camera.DesiredPositionOffset = new Vector3(0.0f, 800.0f, 1500.0f);
                camera.LookAtOffset = new Vector3(0.0f, 150.0f, 0.0f);
                camera.NearPlaneDistance = 10.0f;
                camera.FarPlaneDistance = 100000.0f;

                currentKeyboardState = new KeyboardState();
                currentGamePadState = new GamePadState();
                currentMouseState = new MouseState();
            }
        }

        /// <summary>
        /// Initiates simulations objects such as robot, ground or camera.
        /// Also update some graphic properties
        /// </summary>
        protected override void Initialize()
        {
            base.Initialize();

            robot = new Robot();
            ground = new Ground();
            robot.Load(Content);
            ground.Load(Content);

            // set initial position of camera
            camera.AspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
                graphics.GraphicsDevice.Viewport.Height;


            // update camera and robot poziotion
            UpdateCameraTarget();
            camera.Update();

            graphics.GraphicsDevice.BlendState = BlendState.AlphaBlend;
            graphics.GraphicsDevice.DepthStencilState  = DepthStencilState.Default;
            graphics.GraphicsDevice.SamplerStates[0] = SamplerState.AnisotropicWrap;
            graphics.ApplyChanges();
        }

        /// <summary>
        /// Update simulation graphic
        /// </summary>
        /// <param name="gameTime">Current time</param>
        protected override void Update(GameTime gameTime)
        {
            currentKeyboardState = Keyboard.GetState();
            currentGamePadState = GamePad.GetState(PlayerIndex.One);
            currentMouseState = Mouse.GetState();

            // just in case 
            if (currentKeyboardState.IsKeyDown(Keys.Escape))
                Exit();

            // testing purpose
            if (currentKeyboardState.IsKeyDown(Keys.R))
                robot.ResetPosition();


            robot.Update(gameTime);
            UpdateCameraTarget();
            base.Update(gameTime);
        }

        /// <summary>
        /// Upadate camera position
        /// </summary>
        private void UpdateCameraTarget()
        {
            camera.TargetPosition = robot.Position;
            camera.TargetDirection = robot.Direction;
            camera.Update();
        }

        /// <summary>
        /// Draw all scene
        /// </summary>
        /// <param name="gameTime">Current time</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice device = graphics.GraphicsDevice;
            device.Clear(Color.CornflowerBlue);
            ground.Draw(camera, Matrix.Identity);
            robot.Draw(camera);
            base.Draw(gameTime);
        } 

        /// <summary>
        /// This method recive command passed to simulation of robot
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sender"></param>
        /// <param name="data"></param>
        protected override void MessageReceived<T>(object sender, ref T data)
        {
            if (data is CommunicationProtocol)
            {
                CommunicationProtocol communicat = data as CommunicationProtocol;

                switch (communicat.Command)
                {
                    case "connect":
                        break;
                    case "power": // power
                        robot.ThrustAmount = communicat.ValueFloat;
                        break;
                    case "tachoLimit": // tachoLomit
                        break;
                    case "turnRatio": // turnRatio
                        Vector2 newTurnRatio = new Vector2(-communicat.ValueFloat, 0);
                        robot.RotationAmount = newTurnRatio;
                        break;
                    case "idle": // Idle
                        robot.ResetPosition();
                        break;
                    case "controlFork": // fork control
                        robot.CannonRotation = -communicat.ValueFloat;
                        break;
                    case "exit": // Exit
                        //ClosePipe();
                        this.Exit();
                        break;
                    default:
                        throw new Exception("Communication error");                   

                }
            }
        }
    }
}
